#include "mut.h"
#include "mutsettings.h"
#include <vector>
#include <algorithm>

#define DLGID_DEVTYPE 0x0010
#define DLGID_WINDOWED 0x0011
#define DLGID_RESOLUTION 0x0012
#define DLGID_REFRESHRATE 0x0013
#define DLGID_BACKBUFFERFMT 0x0014
#define DLGID_DEPTHSTENCILFMT 0x0015
#define DLGID_MULTISAMPLETYPE 0x0016
#define DLGID_MULTISAMPLEQUALITY 0x0017
#define DLGID_VERTEXPROCESSING 0x0018
#define DLGID_RUN 0x0019
#define DLGSETTING_SUCCESS 0x1001
#define DLGSETTING_FAIL 0x1002

struct D3DFMT_STRING{
	D3DFORMAT fmt;
	const WCHAR* strfmt;
};
struct D3DMULTISAMPLETYPE_STRING{
	D3DMULTISAMPLE_TYPE type;
	const WCHAR* strtype;
};
D3DFMT_STRING g_BackBufferFmtStr[] = {
	{D3DFMT_A2R10G10B10,L"D3DFMT_A2R10G10B10"},
	{D3DFMT_A8R8G8B8,L"D3DFMT_A8R8G8B8"},
	{D3DFMT_X8R8G8B8,L"D3DFMT_X8R8G8B8"},
	{D3DFMT_A1R5G5B5,L"D3DFMT_A1R5G5B5"},
	{D3DFMT_X1R5G5B5,L"D3DFMT_X1R5G5B5"},
	{D3DFMT_R5G6B5,L"D3DFMT_R5G6B5"},
	{D3DFMT_UNKNOWN,NULL}
};
vector<D3DFORMAT> g_vBackBufferFmt;

D3DFMT_STRING g_DepthStencilFmtStr[] = {
	{D3DFMT_D16_LOCKABLE,L"D3DFMT_D16_LOCKABLE"},
	{D3DFMT_D32,L"D3DFMT_D32"},
	{D3DFMT_D15S1,L"D3DFMT_D15S1"},
	{D3DFMT_D24S8,L"D3DFMT_D24S8"},
	{D3DFMT_D24X8,L"D3DFMT_D24X8"},
	{D3DFMT_D24X4S4,L"D3DFMT_D24X4S4"},
	{D3DFMT_D32F_LOCKABLE,L"D3DFMT_D32F_LOCKABLE"},
	{D3DFMT_D24FS8,L"D3DFMT_D24FS8"},
	{D3DFMT_D32_LOCKABLE,L"D3DFMT_D32_LOCKABLE"},
	{D3DFMT_D16,L"D3DFMT_D16"},
	{D3DFMT_UNKNOWN,NULL}
};
vector<D3DFORMAT> g_vDepthStencilFmt;

D3DMULTISAMPLETYPE_STRING g_MultiSampleTypeStr[] = {
	{D3DMULTISAMPLE_NONE,L"D3DMULTISAMPLE_NONE"},
	{D3DMULTISAMPLE_NONMASKABLE,L"D3DMULTISAMPLE_NONMASKABLE"},
	{D3DMULTISAMPLE_2_SAMPLES,L"D3DMULTISAMPLE_2_SAMPLES"},
	{D3DMULTISAMPLE_3_SAMPLES,L"D3DMULTISAMPLE_3_SAMPLES"},
	{D3DMULTISAMPLE_4_SAMPLES,L"D3DMULTISAMPLE_4_SAMPLES"},
	{D3DMULTISAMPLE_5_SAMPLES,L"D3DMULTISAMPLE_5_SAMPLES"},
	{D3DMULTISAMPLE_6_SAMPLES,L"D3DMULTISAMPLE_6_SAMPLES"},
	{D3DMULTISAMPLE_7_SAMPLES,L"D3DMULTISAMPLE_7_SAMPLES"},
	{D3DMULTISAMPLE_8_SAMPLES,L"D3DMULTISAMPLE_8_SAMPLES"},
	{D3DMULTISAMPLE_9_SAMPLES,L"D3DMULTISAMPLE_9_SAMPLES"},
	{D3DMULTISAMPLE_10_SAMPLES,L"D3DMULTISAMPLE_10_SAMPLES"},
	{D3DMULTISAMPLE_11_SAMPLES,L"D3DMULTISAMPLE_11_SAMPLES"},
	{D3DMULTISAMPLE_12_SAMPLES,L"D3DMULTISAMPLE_12_SAMPLES"},
	{D3DMULTISAMPLE_13_SAMPLES,L"D3DMULTISAMPLE_13_SAMPLES"},
	{D3DMULTISAMPLE_14_SAMPLES,L"D3DMULTISAMPLE_14_SAMPLES"},
	{D3DMULTISAMPLE_15_SAMPLES,L"D3DMULTISAMPLE_15_SAMPLES"},
	{D3DMULTISAMPLE_16_SAMPLES,L"D3DMULTISAMPLE_16_SAMPLES"},
	{D3DMULTISAMPLE_FORCE_DWORD, NULL}
};
vector< pair<D3DMULTISAMPLE_TYPE,DWORD> > g_vMultiSampleType;
vector< D3DDISPLAYMODE > g_vScreenResolution;
D3DDEVTYPE g_vDevType[] = {D3DDEVTYPE_HAL,D3DDEVTYPE_REF};
DWORD g_vVertexProcessing[] = {D3DCREATE_HARDWARE_VERTEXPROCESSING, D3DCREATE_SOFTWARE_VERTEXPROCESSING};

HRESULT MUTOnUpdateDevType(HWND hwndDlg){
	HWND hwndDevType = GetDlgItem(hwndDlg, DLGID_DEVTYPE);
	SendMessage(hwndDevType,CB_RESETCONTENT,0,0);
	SendMessage(hwndDevType,CB_ADDSTRING,0,(LPARAM)L"HAL");
	SendMessage(hwndDevType,CB_ADDSTRING,0,(LPARAM)L"REF");
	SendMessage(hwndDevType,CB_SETCURSEL,0,0);
	return S_OK;
}
HRESULT MUTOnUpdateWindowed(HWND hwndDlg){
	HWND hwndWindowed = GetDlgItem(hwndDlg, DLGID_WINDOWED);
	SendMessage(hwndWindowed,CB_RESETCONTENT,0,0);
	SendMessage(hwndWindowed,CB_ADDSTRING,0,(LPARAM)L"NO");
	SendMessage(hwndWindowed,CB_ADDSTRING,0,(LPARAM)L"YES");
	SendMessage(hwndWindowed,CB_SETCURSEL,1,0);
	return S_OK;
}
HRESULT MUTOnUpdateResolution(HWND hwndDlg){
	LPDIRECT3D9 pD3D = MUTState()->GetD3DObj();
	if (!pD3D) return E_FAIL;
	g_vScreenResolution.clear();

	HWND hwndResolution = GetDlgItem(hwndDlg, DLGID_RESOLUTION);
	SendMessage(hwndResolution,CB_RESETCONTENT,0,0);

	UINT ModeCount = pD3D->GetAdapterModeCount(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8);
	int iXScreen = GetSystemMetrics(SM_CXSCREEN);
	int iYScreen = GetSystemMetrics(SM_CYSCREEN);
	D3DDISPLAYMODE Mode;
	WCHAR screenstr[32];

	for (UINT i=0; i<ModeCount; i++){
		pD3D->EnumAdapterModes(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8, i, &Mode);
		if (!MUTState()->GetWindowed() || (Mode.Width<=iXScreen&&Mode.Height<=iYScreen)){
			g_vScreenResolution.push_back(Mode);
		}
	}

	if (g_vScreenResolution.size()){

		UINT Width = g_vScreenResolution[0].Width, Height = g_vScreenResolution[0].Height;
		wsprintf(screenstr,L"%d * %d",Width,Height);
		SendMessage(hwndResolution, CB_ADDSTRING, 0, (LPARAM)screenstr);
		for (auto itr = g_vScreenResolution.begin(); itr!=g_vScreenResolution.end(); itr++){
			if (itr->Width!=Width||itr->Height!=Height){
				Width = itr->Width;
				Height = itr->Height;
				wsprintf(screenstr,L"%d * %d",Width,Height);
				SendMessage(hwndResolution, CB_ADDSTRING, 0, (LPARAM)screenstr);
			}
		}

		int i=0, index=0;
		Width = g_vScreenResolution[0].Width, Height = g_vScreenResolution[0].Height;
		for (; i<g_vScreenResolution.size(); i++){
			if (g_vScreenResolution[i].Width != Width || 
				g_vScreenResolution[i].Height != Height){
					Width = g_vScreenResolution[i].Width;
					Height = g_vScreenResolution[i].Height;
					index++;
			}
			if (Width == MUTState()->GetD3DPP_BackBufferWidth() && 
				Height == MUTState()->GetD3DPP_BackBufferHeight()){
					SendMessage(hwndResolution, CB_SETCURSEL, index, 0);
					break;
			}
		}

		if (i>=g_vScreenResolution.size()){
			SendMessage(hwndResolution, CB_SETCURSEL, index, 0);
			MUTState()->SetD3DPP_BackBufferWidth(Width);
			MUTState()->SetD3DPP_BackBufferHeight(Height);
		}
	}else{
		SendMessage(hwndResolution, CB_SETCURSEL, -1, 0);
		MUTState()->SetD3DPP_BackBufferWidth(0);
		MUTState()->SetD3DPP_BackBufferHeight(0);
	}
	return S_OK;
}
HRESULT MUTOnUpdateRefreshRate(HWND hwndDlg){
	HWND hwndRefreshRate = GetDlgItem(hwndDlg, DLGID_REFRESHRATE);
	SendMessage(hwndRefreshRate,CB_RESETCONTENT,0,0);
	WCHAR screenstr[32];
	if (!MUTState()->GetWindowed()&&g_vScreenResolution.size()){
		EnableWindow(hwndRefreshRate,TRUE);

		int iRateStart=-1,iRateEnd=-1;
		for (int i=0; i<g_vScreenResolution.size(); i++){
			if (g_vScreenResolution[i].Width == MUTState()->GetD3DPP_BackBufferWidth() &&
				g_vScreenResolution[i].Height == MUTState()->GetD3DPP_BackBufferHeight()){
					wsprintf(screenstr,L"%d Hz",g_vScreenResolution[i].RefreshRate);
					SendMessage(hwndRefreshRate, CB_ADDSTRING, 0, (LPARAM)screenstr);
					if (iRateStart==-1) iRateStart = i;
			}
			if (iRateStart!=-1){
				if (g_vScreenResolution[i].Width == MUTState()->GetD3DPP_BackBufferWidth() &&
					g_vScreenResolution[i].Height == MUTState()->GetD3DPP_BackBufferHeight()){
						iRateEnd = i;
				}
			}
		}
		if (iRateEnd == -1) iRateEnd = g_vScreenResolution.size();

		if (iRateStart!=-1){
			int i=iRateStart; 
			for (; i<=iRateEnd; i++){
				if (g_vScreenResolution[i].RefreshRate == MUTState()->GetD3DPP_FullScreen_RefreshRateInHz()){
					SendMessage(hwndRefreshRate,CB_SETCURSEL,i-iRateStart,0);
					break;
				}
			}
			if (i>=iRateEnd){
				i--;
				SendMessage(hwndRefreshRate,CB_SETCURSEL,i-iRateStart,0);
				MUTState()->SetD3DPP_FullScreen_RefreshRateInHz(g_vScreenResolution[i].RefreshRate);
			}
		}
	}else{
		EnableWindow(hwndRefreshRate,FALSE);
		MUTState()->SetD3DPP_FullScreen_RefreshRateInHz(0);
	}
	return S_OK;
}

HRESULT MUTOnUpdateBackBufferFormat(HWND hwndDlg){
	LPDIRECT3D9 pD3D = MUTState()->GetD3DObj();
	if (!pD3D) return E_FAIL;
	g_vBackBufferFmt.clear();

	HWND hwndBackBufferFMT = GetDlgItem(hwndDlg, DLGID_BACKBUFFERFMT);
	SendMessage(hwndBackBufferFMT,CB_RESETCONTENT,0,0);

	for (D3DFMT_STRING* pFmtStr = g_BackBufferFmtStr; pFmtStr->strfmt; pFmtStr++){
		if (pD3D->CheckDeviceType(D3DADAPTER_DEFAULT,
			MUTState()->GetDevType(), D3DFMT_X8R8G8B8,
			pFmtStr->fmt, MUTState()->GetWindowed()) == D3D_OK){
				SendMessage(hwndBackBufferFMT, CB_ADDSTRING, 0, (LPARAM)pFmtStr->strfmt);
				g_vBackBufferFmt.push_back(pFmtStr->fmt);
		}
	}

	if (g_vBackBufferFmt.size()){
		int i=0; 
		for (; i<g_vBackBufferFmt.size(); i++){
			if (g_vBackBufferFmt[i] == MUTState()->GetD3DPP_BackBufferFormat()){
				SendMessage(hwndBackBufferFMT, CB_SETCURSEL, i, 0);
				break;
			}
		}
		if (i>=g_vBackBufferFmt.size()){
			SendMessage(hwndBackBufferFMT, CB_SETCURSEL, 0, 0);
			MUTState()->SetD3DPP_BackBufferFormat(g_vBackBufferFmt[0]);
		}
	}else{
		SendMessage(hwndBackBufferFMT, CB_SETCURSEL, -1, 0);
		MUTState()->SetD3DPP_BackBufferFormat(D3DFMT_UNKNOWN);
	}
	return S_OK;
}

HRESULT MUTOnUpdateDepthStencilFormat(HWND hwndDlg){
	LPDIRECT3D9 pD3D = MUTState()->GetD3DObj();
	if (!pD3D) return E_FAIL;
	g_vDepthStencilFmt.clear();

	HWND hwndDepthStencilFMT = GetDlgItem(hwndDlg, DLGID_DEPTHSTENCILFMT);
	SendMessage(hwndDepthStencilFMT,CB_RESETCONTENT,0,0);

	if (MUTState()->GetD3DPP_BackBufferFormat()!=D3DFMT_UNKNOWN){
		for (D3DFMT_STRING* pFmtStr = g_DepthStencilFmtStr; pFmtStr->strfmt; pFmtStr++){
			if (pD3D->CheckDepthStencilMatch(D3DADAPTER_DEFAULT,
				MUTState()->GetDevType(), D3DFMT_X8R8G8B8,
				MUTState()->GetD3DPP_BackBufferFormat(), pFmtStr->fmt) == D3D_OK){
					SendMessage(hwndDepthStencilFMT, CB_ADDSTRING, 0, (LPARAM)pFmtStr->strfmt);
					g_vDepthStencilFmt.push_back(pFmtStr->fmt);
			}
		}
	}

	if (g_vDepthStencilFmt.size()){
		int i=0;
		for (; i<g_vDepthStencilFmt.size(); i++){
			if (g_vDepthStencilFmt[i] == MUTState()->GetD3DPP_AutoDepthStencilFormat()){
				SendMessage(hwndDepthStencilFMT, CB_SETCURSEL, i, 0);
				break;
			}
		}
		if (i>=g_vDepthStencilFmt.size()){
			SendMessage(hwndDepthStencilFMT, CB_SETCURSEL, 0, 0);
			MUTState()->SetD3DPP_AutoDepthStencilFormat(g_vDepthStencilFmt[0]);
		}
	}else{
		SendMessage(hwndDepthStencilFMT, CB_SETCURSEL, -1, 0);
		MUTState()->SetD3DPP_AutoDepthStencilFormat(D3DFMT_UNKNOWN);
	}
	return S_OK;
}

HRESULT MUTOnUpdateMultiSampleType(HWND hwndDlg){
	LPDIRECT3D9 pD3D = MUTState()->GetD3DObj();
	if (!pD3D) return E_FAIL;
	g_vMultiSampleType.clear();

	HWND hwndMultiSampleType = GetDlgItem(hwndDlg, DLGID_MULTISAMPLETYPE);
	SendMessage(hwndMultiSampleType,CB_RESETCONTENT,0,0);

	if ( MUTState()->GetD3DPP_BackBufferFormat()!=D3DFMT_UNKNOWN && 
		MUTState()->GetD3DPP_AutoDepthStencilFormat()!=D3DFMT_UNKNOWN ){
			for (D3DMULTISAMPLETYPE_STRING* pTypeStr = g_MultiSampleTypeStr;
				pTypeStr->strtype; pTypeStr++){
					DWORD dwBBQuality = 0;
					DWORD dwDSQuality = 0;
					if ((pD3D->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT,
						MUTState()->GetDevType(), MUTState()->GetD3DPP_BackBufferFormat(), MUTState()->GetWindowed(), pTypeStr->type, &dwBBQuality) == D3D_OK) &&
						(pD3D->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT,
						MUTState()->GetDevType(), MUTState()->GetD3DPP_AutoDepthStencilFormat(), MUTState()->GetWindowed(), pTypeStr->type, &dwDSQuality) == D3D_OK)){
							SendMessage(hwndMultiSampleType, CB_ADDSTRING, 0, (LPARAM)pTypeStr->strtype);
							g_vMultiSampleType.push_back(make_pair(pTypeStr->type, min(dwBBQuality,dwDSQuality)));
					}
			}
	}

	if (g_vMultiSampleType.size()){
		int i=0;
		for (; i<g_vMultiSampleType.size(); i++){
			if (g_vMultiSampleType[i].first == MUTState()->GetD3DPP_MultiSampleType()){
				SendMessage(hwndMultiSampleType, CB_SETCURSEL, i, 0);
				break;
			}
		}
		if (i>=g_vMultiSampleType.size()){
			SendMessage(hwndMultiSampleType, CB_SETCURSEL, 0, 0);
			MUTState()->SetD3DPP_MultiSampleType(g_vMultiSampleType[0].first);
		}
	}else{
		SendMessage(hwndMultiSampleType, CB_SETCURSEL, -1, 0);
		MUTState()->SetD3DPP_MultiSampleType(D3DMULTISAMPLE_FORCE_DWORD);
	}

	return S_OK;
}

HRESULT MUTOnUpdateMultiSampleQuality(HWND hwndDlg){
	HWND hwndMultiSampleQuality = GetDlgItem(hwndDlg, DLGID_MULTISAMPLEQUALITY);
	SendMessage(hwndMultiSampleQuality,CB_RESETCONTENT,0,0);

	if (g_vMultiSampleType.size()){
		DWORD dwMaxQuality=0;
		for (auto itr = g_vMultiSampleType.begin(); itr != g_vMultiSampleType.end(); itr++){
			if (itr->first == MUTState()->GetD3DPP_MultiSampleType()){
				dwMaxQuality = itr->second;
				break;
			}
		}
		if (dwMaxQuality<=0) return S_OK;
		MUTState()->SetMaxMultiSampleQuality(dwMaxQuality);

		WCHAR strtmp[32];
		BOOL bSet = FALSE;
		for (DWORD i=0; i<MUTState()->GetMaxMultiSampleQuality(); i++){
			wsprintf(strtmp, L"%d", i);
			SendMessage(hwndMultiSampleQuality, CB_ADDSTRING, 0, (LPARAM)strtmp);
		}
		if (MUTState()->GetD3DPP_MultiSampleQuality() < MUTState()->GetMaxMultiSampleQuality())
			SendMessage(hwndMultiSampleQuality, CB_SETCURSEL, MUTState()->GetD3DPP_MultiSampleQuality(), 0);
		else{
			SendMessage(hwndMultiSampleQuality, CB_SETCURSEL, 0, 0);
			MUTState()->SetD3DPP_MultiSampleQuality(0);
		}
	}
	return S_OK;
}

HRESULT MUTOnUpdateVertexProcessing(HWND hwndDlg){
	HWND hwndVertexProcessing = GetDlgItem(hwndDlg, DLGID_VERTEXPROCESSING);
	SendMessage(hwndVertexProcessing, CB_ADDSTRING, 0, (LPARAM)L"Hardware");
	SendMessage(hwndVertexProcessing, CB_ADDSTRING, 0, (LPARAM)L"Software");
	SendMessage(hwndVertexProcessing, CB_SETCURSEL, 0, 0);
	return S_OK;
}

HRESULT MUTOnChangeDevType(HWND hwndDlg, D3DDEVTYPE DevType){
	if (MUTState()->GetDevType() != DevType){
		MUTState()->SetDevType(DevType);
		MUTOnUpdateBackBufferFormat(hwndDlg);
		MUTOnUpdateDepthStencilFormat(hwndDlg);
		MUTOnUpdateMultiSampleType(hwndDlg);
		MUTOnUpdateMultiSampleQuality(hwndDlg);
	}
	return S_OK;
}
HRESULT MUTOnChangeWindowed(HWND hwndDlg, BOOL bWindowed){
	if (MUTState()->GetWindowed() != bWindowed){
		MUTState()->SetWindowed(bWindowed);
		MUTState()->SetD3DPP_Windowed(bWindowed);
		MUTOnUpdateResolution(hwndDlg);
		MUTOnUpdateRefreshRate(hwndDlg);
		MUTOnUpdateBackBufferFormat(hwndDlg);
		MUTOnUpdateDepthStencilFormat(hwndDlg);
		MUTOnUpdateMultiSampleType(hwndDlg);
		MUTOnUpdateMultiSampleQuality(hwndDlg);
	}
	return S_OK;
}
HRESULT MUTOnChangeResolution(HWND hwndDlg, int iCurSel){
	if (!g_vScreenResolution.size()) return E_FAIL;

	int iWidth = g_vScreenResolution[0].Width;
	int iHeight = g_vScreenResolution[0].Height;
	iCurSel--;
	for (auto itr = g_vScreenResolution.begin(); itr!=g_vScreenResolution.end()&&iCurSel>=0; itr++){
		if (itr->Width!=iWidth||itr->Height!=iHeight){
			iWidth = itr->Width;
			iHeight = itr->Height;
			iCurSel--;
		}
	}
	if (iCurSel>=0) return E_FAIL;

	if (MUTState()->GetD3DPP_BackBufferWidth()!=iWidth||
		MUTState()->GetD3DPP_BackBufferHeight()!=iHeight){
			MUTState()->SetD3DPP_BackBufferWidth(iWidth);
			MUTState()->SetD3DPP_BackBufferHeight(iHeight);
			MUTOnUpdateRefreshRate(hwndDlg);
	}
	return S_OK;
}
HRESULT MUTOnChangeRefreshRate(HWND hwndDlg, int iCurSel){
	if (!g_vScreenResolution.size()) return E_FAIL;
	int i=0;
	for (; i<g_vScreenResolution.size(); i++){
		if (g_vScreenResolution[i].Width==MUTState()->GetD3DPP_BackBufferWidth()&&
			g_vScreenResolution[i].Height==MUTState()->GetD3DPP_BackBufferHeight())
			break;
	}

	MUTState()->SetD3DPP_FullScreen_RefreshRateInHz(g_vScreenResolution[i+iCurSel].RefreshRate);
	return S_OK;
}
HRESULT MUTOnChangeBackBufferFormat(HWND hwndDlg, D3DFORMAT fmt){
	if (MUTState()->GetD3DPP_BackBufferFormat() != fmt){
		MUTState()->SetD3DPP_BackBufferFormat(fmt);
		MUTOnUpdateDepthStencilFormat(hwndDlg);
		MUTOnUpdateMultiSampleType(hwndDlg);
		MUTOnUpdateMultiSampleQuality(hwndDlg);
	}
	return S_OK;
}
HRESULT MUTOnChangeDepthStencilFormat(HWND hwndDlg, D3DFORMAT fmt){
	if (MUTState()->GetD3DPP_AutoDepthStencilFormat() != fmt){
		MUTState()->SetD3DPP_AutoDepthStencilFormat(fmt);
		MUTOnUpdateMultiSampleType(hwndDlg);
		MUTOnUpdateMultiSampleQuality(hwndDlg);
	}
	return S_OK;
}
HRESULT MUTOnChangeMultiSampleType(HWND hwndDlg, D3DMULTISAMPLE_TYPE type){
	if (MUTState()->GetD3DPP_MultiSampleType() != type){
		MUTState()->SetD3DPP_MultiSampleType(type);
		MUTOnUpdateMultiSampleQuality(hwndDlg);
	}
	return S_OK;
}
HRESULT MUTOnChangeMultiSampleQuality(HWND hwndDlg, DWORD dwQuality){
	MUTState()->SetD3DPP_MultiSampleQuality(dwQuality);
	return S_OK;
}
HRESULT MUTOnChangeVertexProcessing(HWND hwndDlg, DWORD type){
	MUTState()->SetVertexProcessing(type);
	return S_OK;
}

INT_PTR CALLBACK MUTSettingsDlgProc(
	__in  HWND hwndDlg,
	__in  UINT uMsg,
	__in  WPARAM wParam,
	__in  LPARAM lParam
	){
	switch(uMsg){
	case WM_INITDIALOG:
		{
			LPDIRECT3D9 pD3D = MUTState()->GetD3DObj();
			if ( !pD3D ) return TRUE;

			MUTOnUpdateDevType(hwndDlg);
			MUTOnUpdateWindowed(hwndDlg);
			MUTOnUpdateResolution(hwndDlg);
			MUTOnUpdateRefreshRate(hwndDlg);
			MUTOnUpdateBackBufferFormat(hwndDlg);
			MUTOnUpdateDepthStencilFormat(hwndDlg);
			MUTOnUpdateMultiSampleType(hwndDlg);
			MUTOnUpdateMultiSampleQuality(hwndDlg);
			MUTOnUpdateVertexProcessing(hwndDlg);

			RECT rtDlg;
			GetWindowRect(hwndDlg,&rtDlg);
			SetWindowPos(hwndDlg,0,
				(GetSystemMetrics(SM_CXSCREEN)-rtDlg.right+rtDlg.left)/2,
				(GetSystemMetrics(SM_CYSCREEN)-rtDlg.bottom+rtDlg.top)/2,
				0,0,SWP_NOSIZE);

		}
		return TRUE;
	case WM_COMMAND:
		switch (HIWORD(wParam)){
		case CBN_SELCHANGE:
			{
				int iCurSel = SendMessage((HWND)lParam,CB_GETCURSEL,0,0);
				switch (LOWORD(wParam)){
				case DLGID_DEVTYPE:
					MUTOnChangeDevType(hwndDlg,g_vDevType[iCurSel]);
					return TRUE;
				case DLGID_WINDOWED:
					MUTOnChangeWindowed(hwndDlg,(BOOL)iCurSel);
					return TRUE;
				case DLGID_RESOLUTION:
					MUTOnChangeResolution(hwndDlg,iCurSel);
					return TRUE;
				case DLGID_REFRESHRATE:
					MUTOnChangeRefreshRate(hwndDlg,iCurSel);
					return TRUE;
				case DLGID_BACKBUFFERFMT:
					MUTOnChangeBackBufferFormat(hwndDlg,g_vBackBufferFmt[iCurSel]);
					return TRUE;
				case DLGID_DEPTHSTENCILFMT:
					MUTOnChangeDepthStencilFormat(hwndDlg,g_vDepthStencilFmt[iCurSel]);
					return TRUE;
				case DLGID_MULTISAMPLETYPE:
					MUTOnChangeMultiSampleType(hwndDlg,g_vMultiSampleType[iCurSel].first);
					return TRUE;
				case DLGID_MULTISAMPLEQUALITY:
					MUTOnChangeMultiSampleQuality(hwndDlg,iCurSel);
					return TRUE;
				case DLGID_VERTEXPROCESSING:
					MUTOnChangeVertexProcessing(hwndDlg,g_vVertexProcessing[iCurSel]);
					return TRUE;
				}
				return TRUE;
			}
			break;
		case BN_CLICKED:
			switch (LOWORD(wParam)){
			case DLGID_RUN:
				EndDialog(hwndDlg,DLGSETTING_SUCCESS);
				return TRUE;
			}
			break;
		}
		break;
	case WM_CLOSE:
		EndDialog(hwndDlg,DLGSETTING_FAIL);
		return TRUE;
	}
	return FALSE;
}

LPWORD MUTDWORDAlign(LPWORD ptr){
	DWORD v = (DWORD)ptr;
	v +=2;
	v >>=2;
	v <<=2;
	return (LPWORD)v;
}

LPWORD MUTWORDAlign(LPWORD ptr){
	DWORD v = (DWORD)ptr;
	v ++;
	v >>=1;
	v <<=1;
	return (LPWORD)v;
}

const WORD NumOfSetting = 9;
WORD g_DlgItemID[NumOfSetting] = {
	DLGID_DEVTYPE,
	DLGID_WINDOWED,
	DLGID_RESOLUTION,
	DLGID_REFRESHRATE,
	DLGID_BACKBUFFERFMT,
	DLGID_DEPTHSTENCILFMT,
	DLGID_MULTISAMPLETYPE,
	DLGID_MULTISAMPLEQUALITY,
	DLGID_VERTEXPROCESSING};
const WCHAR* g_DlgItemString[NumOfSetting] = {
	L"Device",
	L"Windowed",
	L"Resolution",
	L"Refresh",
	L"BackBuffer",
	L"DepthStencil",
	L"MultiSample",
	L"SampleQuality",
	L"VertexProcessing"
};

HRESULT MUTDialogItemTemplateEx(LPWORD& lpw,DWORD helpID,DWORD exStyle,DWORD style,short x,short y,short cx,short cy,DWORD id,WORD windowClass,const WCHAR* title){
	lpw = MUTDWORDAlign(lpw);
	*(LPDWORD)lpw = 0; // helpID
	lpw+=2;
	*(LPDWORD)lpw = exStyle; // exStyle
	lpw+=2;
	*(LPDWORD)lpw = style; // Style
	lpw+=2;
	*lpw++ = x; // x
	*lpw++ = y; //y
	*lpw++ = cx; //cx
	*lpw++ = cy; //cy
	*(LPDWORD)lpw = id; // id
	lpw+=2;
	*lpw++ = 0xFFFF;
	*lpw++ = windowClass;   // window class
	// title
	LPWSTR lpwstr = (LPWSTR)lpw;
	int nchar = lstrlen(title)+1;
	lstrcpy(lpwstr,title);
	lpw += nchar;
	*lpw++ = 0;   // No creation data
	return S_OK;
}

HRESULT MUTDialogSettings(){

	HGLOBAL hGlobal = GlobalAlloc(GMEM_ZEROINIT,1024);
	if (!hGlobal) {
		MUTWinErrorTrace(GetLastError());
		return E_FAIL;
	}
	LPWORD lpw = (LPWORD)GlobalLock(hGlobal);
	*lpw++ = 1;			// dlgVer 
	*lpw++ = 0xFFFF;	// signature 
	lpw+=2;				// helpID = 0 (DWORD)
	lpw+=2;				// exStyle = 0 (DWORD)
	*(LPDWORD)lpw = WS_POPUP | WS_BORDER | WS_SYSMENU | DS_SETFONT | DS_MODALFRAME | WS_CAPTION;
	lpw+=2;
	*lpw++ = NumOfSetting*2+1; // cDlgItems 
	*lpw++ = 0;		// x 
	*lpw++ = 0;		// y
	*lpw++ = 210;		// cx
	*lpw++ = 210;		// cy
	lpw++;				// menu = 0 (no menus)
	lpw++;				// class = 0 (predefined class)

	//Title
	LPWSTR lpwstr = (LPWSTR)lpw;
	int nchar = MultiByteToWideChar(CP_ACP, 0, "Settings", -1, lpwstr, 50);
	lpw += nchar;

	*lpw++ = 10;		// point size
	*lpw++ = FW_NORMAL; // weight
	*LPBYTE(lpw) = 0;	// italic (BYTE)
	*(LPBYTE(lpw)+1) = ANSI_CHARSET; // charset (BYTE)
	lpw++;

	//typeface
	lpwstr = (LPWSTR)lpw;
	nchar = MultiByteToWideChar(CP_ACP, 0, "Tahoma", -1, lpwstr, 50);
	lpw += nchar;

	for (WORD i=0; i<NumOfSetting; i++){
		MUTDialogItemTemplateEx(
			lpw,
			0,			// helpID
			0,			// exStyle
			WS_CHILD | WS_VISIBLE | SS_LEFT, // style
			5,			// x
			12+i*20,	// y
			65,			// cx
			50,			// cy
			0,			//id
			0x0082,		//static control
			g_DlgItemString[i]);
	}

	for (WORD i=0; i<NumOfSetting; i++){
		MUTDialogItemTemplateEx(
			lpw,
			0,			// helpID
			0,			// exStyle
			WS_CHILD | WS_VISIBLE | WS_VSCROLL | CBS_DROPDOWNLIST, // style
			70,			// x
			10+i*20,	// y
			130,		// cx
			50,			// cy
			g_DlgItemID[i], //id
			0x0085,		// combobox control
			L"");
	}

	MUTDialogItemTemplateEx(
		lpw,
		0,			// helpID
		0,			// exStyle
		WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, // style
		75,			// x
		10+NumOfSetting*20,	// y
		50,			// cx
		15,			// cy
		DLGID_RUN,	//id
		0x0080,		// button control
		L"Run");

	GlobalUnlock(hGlobal);
	INT i = DialogBoxIndirect(GetModuleHandle(0),(LPDLGTEMPLATE)hGlobal,NULL,MUTSettingsDlgProc);
	if (i == -1){
		MUTWinErrorTrace(GetLastError());
		return E_FAIL;
	}

	GlobalFree(hGlobal);
	if (i == 0){
		MUTErrorTrace(L"Invalid hwndParent Params!");
		return E_FAIL;
	}else if (i == DLGSETTING_SUCCESS){
		return S_OK;
	}else if (i == DLGSETTING_FAIL){
		return E_FAIL;
	}
	return S_OK;
}
